from typing import Dict, Any
from enum import Enum
from pydantic import BaseModel
import logging

logger = logging.getLogger(__name__)


class TaskStatus(str, Enum):
    PENDING = "pending"
    READY = "ready"
    RUNNING = "running"
    COMPLETED = "completed"
    FAILED = "failed"
    CANCELLED = "cancelled"


class TaskSpec(BaseModel):
    """
    This is a internal specification for a task. that should be stored in the database.

    name: the name of the task, defined by the user, not unique.
    commit: the commit hash of the code to run, should be a valid git commit hash.
    fetch_url: the url to fetch the code from, should be a valid git url.
    task: the python module/function to run, should be a valid python function, like modname.submodname.funcname.
    task_hash: the hash of the task, used to track changes of the related code.
    file_params: the parameters passed as file paths. can be :file_id for a file uploaded by the user,
        or task_hash:file_name for a file generated by a task.
        The files should be opened read-only.
    value_params: the parameters passed as values defined in the configuration.
    output_params: the parameters passed as the output of other tasks.
    status: the status of the task.
    """

    name: str = ''
    commit: str
    fetch_url: str
    task: str
    task_hash: str
    file_params: Dict[str, str]
    value_params: Dict[str, Any]
    output_params: Dict[str, str]
    status: TaskStatus = TaskStatus.PENDING

    def get_dependent_task_hashes(self) -> set[str]:
        """Get all dependent task hashes from file_params and output_params.
        
        Returns:
            set[str]: Set of task hashes that this task depends on
        """
        dependent_hashes = set()
        
        # Get dependencies from file_params
        for param_value in self.file_params.values():
            if ":" in param_value and not param_value.startswith(":"):  # Skip user uploaded files (:file_id)
                dep_task_hash = param_value.split(":", 1)[0]
                dependent_hashes.add(dep_task_hash)
        
        # Get dependencies from output_params
        dependent_hashes.update(self.output_params.values())
        
        return dependent_hashes

